package com.cloudkinto.service.stock.impl;

import cn.afterturn.easypoi.excel.entity.ExportParams;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cloudkinto.common.BeanConvert;
import com.cloudkinto.common.DicBusinessConstant;
import com.cloudkinto.common.DicBusinessItemConstant;
import com.cloudkinto.common.constant.SysConstant;
import com.cloudkinto.common.error.ErrorEnum;
import com.cloudkinto.common.exception.BizException;
import com.cloudkinto.common.exception.BizExceptionI18;
import com.cloudkinto.common.exception.NotSufficientFundsException;
import com.cloudkinto.common.utils.ExcelUtils;
import com.cloudkinto.common.utils.MathUtils;
import com.cloudkinto.common.utils.StringsUtil;
import com.cloudkinto.common.utils.TimeUtils;
import com.cloudkinto.common.utils.ali.AliOss;
import com.cloudkinto.common.web.PageResult;
import com.cloudkinto.common.web.SingleResult;
import com.cloudkinto.dao.*;
import com.cloudkinto.entity.*;
import com.cloudkinto.extentity.*;
import com.cloudkinto.extentity.stockday.StockDayTotalDto;
import com.cloudkinto.extentity.stockday.StockHistoryDaysDto;
import com.cloudkinto.service.dic.DicBusinessItemService;
import com.cloudkinto.service.file.FileService;
import com.cloudkinto.service.finance.CompanyAccountService;
import com.cloudkinto.service.finance.vo.IdAndNameEntity;
import com.cloudkinto.service.orderback.OrderBackService;
import com.cloudkinto.service.orderoutput.OrderOutputService;
import com.cloudkinto.service.orderoutput.openapivo.OpenApiOrderOutputAddReq;
import com.cloudkinto.service.orderoutput.openapivo.OpenApiOrderOutputProductAddReq;
import com.cloudkinto.service.orderoutput.vo.OrderOutputAddReq;
import com.cloudkinto.service.orderoutput.vo.OrderOutputPackageAddReq;
import com.cloudkinto.service.orderoutput.vo.OrderOutputProductAddReq;
import com.cloudkinto.service.region.JpRegionService;
import com.cloudkinto.service.shop.ShopService;
import com.cloudkinto.service.stock.StockLogService;
import com.cloudkinto.service.stock.StockRecordService;
import com.cloudkinto.service.stock.StockSnapshotExportVo;
import com.cloudkinto.service.stock.StockTransferService;
import com.cloudkinto.service.stock.vo.StockRecordDetailRes;
import com.cloudkinto.service.stock.vo.StockTurnoverRatePageRes;
import com.cloudkinto.service.stock.vo.record.ProductStockExportVo;
import com.cloudkinto.service.stock.vo.record.StockRecordExportVo;
import com.cloudkinto.service.stock.vo.record.StockRecordPageRes;
import com.cloudkinto.service.stock.vo.record.StockRecordSendReq;
import com.cloudkinto.service.stock.vo.transfer.StockTransferAddReq;
import com.cloudkinto.service.stock.vo.transfer.StockTransferProductAdd;
import com.cloudkinto.service.storage.StorageService;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * service实现类
 * </p>
 *
 * @author 张永远
 * @since 2020-06-10
 */
@Service
@Transactional(rollbackFor = Exception.class)//事务回滚
public class StockRecordServiceImpl extends ServiceImpl<StockRecordDao, StockRecordDo> implements StockRecordService {
    @Autowired
    private StockRecordDao dao;
    @Autowired
    private ShopDao shopDao;
    @Autowired
    private StorageDao storageDao;
    @Autowired
    private OrderOutputDao orderOutputDao;
    @Autowired
    private OrderOutputPackageDao orderOutputPackageDao;
    @Autowired
    private OrderOutputProductDao orderOutputProductDao;
    @Autowired
    private ProductInfoDao productInfoDao;
    @Autowired
    private UserDao userDao;
    @Autowired
    private JpRegionService regionService;
    @Autowired
    private ShopService shopService;
    @Autowired
    @Lazy
    private OrderOutputService orderOutputService;
    @Autowired
    private CompanyAccountService companyAccountService;
    @Autowired
    private DicBusinessItemDao dicBusinessItemDao;
    @Autowired
    private DicBusinessItemService dicBusinessItemService;
    @Autowired
    private StorageService storageService;
    @Autowired
    private CompanyDao companyDao;
    @Autowired
    private ExchangeRateDao rateDao;
    @Autowired
    private StockLogService stockLogService;
    @Autowired
    private ProductStockRackDao productStockRackDao;
    @Autowired
    private FileService fileService;
    @Value("${gbc.uploadPath.fileUrl}")
    private String fileUrl;

    @Value("${gbc.uploadPath.filePathTemp}")
    private String filePathTemp;
    @Autowired
    private StockTransferService stockTransferService;
    @Autowired
    private OrderBackService orderBackService;

    @Override
    public SingleResult updateInit(Long id) {
        return SingleResult.success("");
    }

    @Override
    public Object update(Object req, Long userId) {
        /*StockRecordDo entityDo = dao.selectById(req.getId());
        BeanUtils.copyProperties(req, entityDo);
        handlerUpdateBefore(entityDo, userId);
        dao.updateById(entityDo);
        return handlerUpdateAfter(entityDo);*/
        return null;
    }

    //编辑校验
    private void updateCheck(Object req) {

    }

    //做修改之前要执行的业务定制处理
    private void handlerUpdateBefore(StockRecordDo entityDo, Long userId) {
        entityDo.setUpdateBy(userId);
        entityDo.setUpdateTime(new Date());
    }

    //做修改之后要执行的业务定制处理
    private Object handlerUpdateAfter(StockRecordDo entityDo) {
        Object res = new Object();
        BeanUtils.copyProperties(entityDo, res);
        return res;
    }

    @Override
    public int delete(Long id, Long userId) {
        throw new BizExceptionI18(SysConstant.NO_PERMISSION);
//        StockRecordDo entityDo = dao.selectById(id);
//        handlerDeleteBefore(entityDo, userId);
//        dao.selectById(entityDo);
//        return 1;
    }

    //做删除之前要执行的业务定制处理
    private void handlerDeleteBefore(StockRecordDo entityDo, Long userId) {
        entityDo.setDeleteBy(userId);
        entityDo.setDeleteTime(new Date());
    }

    @Override
    public StockRecordDetailRes detail(Long id, Long companyId) {
        StockRecordDo entityDo = dao.selectById(id);
        StockRecordDetailRes res = new StockRecordDetailRes();
        ProductInfoDo productInfoDo = productInfoDao.selectById(entityDo.getProductInfoId());
        BeanUtils.copyProperties(productInfoDo, res);
        DicBusinessItemDo dicBusinessItemDo = dicBusinessItemDao.selectById(productInfoDo.getProductType());
        if (dicBusinessItemDo != null)
            res.setProductType(dicBusinessItemDo.getDicItemValue());
        res.setSize(productInfoDo.getLength() + "+" + productInfoDo.getWidth() + "+" + productInfoDo.getHeight());
        res.setProductUrl(fileService.getFilePath(productInfoDo.getProductPictureFileId()));
        Map<String, String> map = new HashMap<>();
        map.put("productId", entityDo.getProductInfoId() + "");
        map.put("shopId", entityDo.getShopId() + "");
        map.put("storageId", entityDo.getStorageId() + "");
        res.setStockLogList(stockLogService.listPageLast10(map).getData());

        Map<String, Integer> stockAge = stockAge(id);
        res.setV1Count(stockAge.get("v1Count"));
        res.setV2Count(stockAge.get("v2Count"));
        res.setV3Count(stockAge.get("v3Count"));

        map.put("companyId", companyId+"");
        //获取库存详情
        List<ProductStockExportVo> stockList = new ArrayList<>();
        if (productInfoDo.getOutType() == 2) {
            //展示真实的库存先进先出情况
            stockList = this.getStockExportListReal(map);
        }
        else {
            //展示理论的先进先出情况
            stockList = this.getStockExportList(map);
        }
        res.setStockAgeList(stockList);
        return res;
    }

    //查询明细之后要执行的业务定制处理
    private StockRecordDetailRes handlerDetailAfter(StockRecordDetailRes res) {
        return res;
    }

    @Override
    public SingleResult pageInit(Long companyId, Long userId) {
        Map map = new HashMap();
        List<Map> shopList = shopService.selectShopListInit(userId, companyId);
        List<Map> storageList = storageService.storageList();
        map.put("productTypeList", dicBusinessItemService.getDicItemList(DicBusinessConstant.productType));
        map.put("shopList", shopList);
        map.put("storageList", storageList);
        return SingleResult.success(map);
    }

    @Override
    public List<StockRecordPageRes> getList(Map<String, String> map) {
        List<StockRecordPageDto> pageDtoList = dao.listPage(map);
        List<StockRecordPageRes> resList = handlerListAfter(pageDtoList);
        return resList;
    }

    @Override
    public void exportStockRecord(Map<String, String> map, HttpServletResponse response) {
        CompanyDo companyDo = companyDao.selectById(map.get("companyId"));
        if (companyDo == null) {
            throw new BizException(SysConstant.Login_Error_Company);
        }
        List<StockRecordDto> resList = dao.getStockRecord(map);

        List<StockRecordExportVo> exportVoList = new ArrayList<>();
        for (StockRecordDto et : resList) {
            StockRecordExportVo exportVo = new StockRecordExportVo();
            BeanUtils.copyProperties(et, exportVo);
            exportVoList.add(exportVo);
        }

        ExportParams exportParams = new ExportParams();
        exportParams.setCreateHeadRows(true);
        exportParams.setHeaderColor(IndexedColors.YELLOW.getIndex());
        try {
            ExcelUtils.exportExcel(exportVoList, StockRecordExportVo.class, companyDo.getCompanyCode() + "库存一览" + TimeUtils.getCurrentDateTimeFormat(), exportParams, response);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public PageResult getListPage(Map<String, String> map) {

        IPage<StockRecordPageDto> page = pageInit(map);
        List<StockRecordPageDto> pageDtoList = dao.listPage(page, map);
        List<StockRecordPageRes> resList = handlerListAfter(pageDtoList);
        PageResult result = new PageResult(resList, (int) page.getCurrent(), (int) page.getSize(), (int) page.getTotal(), (int) page.getPages());
        return result;
    }

    @Override
    public PageResult getApiListPage(Map<String, String> map) {

        IPage<StockRecordPageDto> page = pageInit(map);
        List<StockRecordPageDto> pageDtoList = dao.listPage(page, map);
        List<StockRecordPageRes> resList = handlerApiListAfter(pageDtoList);
        PageResult result = new PageResult(resList, (int) page.getCurrent(), (int) page.getSize(), (int) page.getTotal(), (int) page.getPages());
        return result;
    }

    private List<StockRecordPageRes> handlerApiListAfter(List<StockRecordPageDto> pageDtoList) {
        List<StockRecordPageRes> result = new ArrayList<>();
        if (!CollectionUtils.isEmpty(pageDtoList)) {
            for (StockRecordPageDto pageDto : pageDtoList) {
                StockRecordPageRes res = new StockRecordPageRes();
                res.setId(pageDto.getId());
                res.setCanotSellCount(pageDto.getCanotSellCount());
                res.setProductInfoId(pageDto.getProductInfoId());
                res.setProductId(pageDto.getProductId());
                res.setProductHeight(pageDto.getHeight());
                res.setProductWidth(pageDto.getWidth());
                res.setProductLength(pageDto.getLength());
                res.setProductWeight(pageDto.getWeight());
                if (pageDto.getFreezeCount() != null) {
                    res.setCanSellCount(pageDto.getCanSellCount() + pageDto.getFreezeCount());
                } else {
                    res.setCanSellCount(pageDto.getCanSellCount());
                }
                res.setCommoditySku(pageDto.getCommoditySku());
                res.setStorageSku(pageDto.getStorageSku());
                res.setStorage(pageDto.getStorageSku());
                res.setShopId(pageDto.getShopId());
                res.setStorageId(pageDto.getStorageId());
                res.setProductName(pageDto.getProductName());
                res.setNoDelivered(pageDto.getNoDelivered() + pageDto.getTurnFba());
                res.setInTransit(pageDto.getInTransit());
                res.setFreezeCount(pageDto.getFreezeCount() == null ? 0 : pageDto.getFreezeCount());
                res.setJustNoDelivered(pageDto.getNoDelivered());
                res.setTurnFba(pageDto.getTurnFba());
                res.setUpdateTime(pageDto.getUpdateTime());
                ShopDo shopDo = shopDao.selectById(pageDto.getShopId());
                if (shopDo != null) {
                    res.setShop(shopDo.getShopName());
                }
                StorageDo storageDo = storageDao.selectById(pageDto.getStorageId());
                if (storageDo != null) {
                    res.setStorage(storageDo.getStorageName());
                }
                result.add(res);
            }
        }
        return result;
    }

    @Override
    public SingleResult sendOutInit() {
        Map map = new HashMap();
        map.put("regioon", regionService.getList(new HashMap<>()));
        List<IdAndNameEntity> idAndNameEntities = new ArrayList<>();
        idAndNameEntities.add(new IdAndNameEntity(0, "普通"));
        idAndNameEntities.add(new IdAndNameEntity(1, "次日达"));
        map.put("shipment", idAndNameEntities);
        return SingleResult.success(map);
    }

    @Override
    public SingleResult sendOut(StockRecordSendReq req, Long userId, Long companyId) {
        //校验余额是否不足
        sufficientFundsCheck(companyId);

        //todo 有些属性需要填充，后续要补上
        StockRecordDo stockRecordDo = dao.selectById(req.getId());
        ProductInfoDo productInfoDo = productInfoDao.selectById(stockRecordDo.getProductInfoId());
        OrderOutputAddReq orderOutputDo = new OrderOutputAddReq();
        orderOutputDo.setOrderType(1);//一件代发
        orderOutputDo.setSendDate(new Date());
        orderOutputDo.setShopId(stockRecordDo.getShopId());
        orderOutputDo.setStorageId(stockRecordDo.getStorageId());
        orderOutputDo.setCompanyId(stockRecordDo.getCompanyId());
        orderOutputDo.setReceiverName(req.getReceiveName());
        orderOutputDo.setTelPhone(req.getTelephone());
        orderOutputDo.setPostCode(req.getPostCode());
        orderOutputDo.setArea(req.getArea());
        orderOutputDo.setAddress(req.getReceiveAddress().replaceAll("\n", ""));
//        orderInputDo.setTips(req.getRemark());
        orderOutputDo.setCod(req.getCod());
        if (StringUtils.isNotBlank(req.getDeliveryDate())) {
            orderOutputDo.setDeliveryDate(req.getDeliveryDate());
        }
        orderOutputDo.setDeliveryTime(req.getDeliveryTime());
        orderOutputDo.setShipmentType(req.getShipmentType());
        orderOutputDo.setOrderNo(req.getOrderNumber().trim());
        List<OrderOutputPackageAddReq> packageAddList = new ArrayList<>();
        OrderOutputPackageAddReq packageAdd = new OrderOutputPackageAddReq();
        orderOutputDo.setPackageList(packageAddList);
        OrderOutputPackageDo packageDo = new OrderOutputPackageDo();
//        packageDo.setLength(null);
//        packageDo.setWidth(null);
//        packageDo.setHeight(null);
//        packageDo.setHeight(null);
//        packageDo.setWeight(null);
        packageDo.setCreateTime(new Date());
        packageDo.setCreateBy(userId);
        packageDo.setDeleteFlag(0);


        List<OrderOutputProductAddReq> productDos = new ArrayList<>();
        OrderOutputProductAddReq productDo = new OrderOutputProductAddReq();
        productDo.setPackageId(packageDo.getId());
        productDo.setProductId(stockRecordDo.getProductInfoId());
        productDo.setCount(req.getCount());
        productDos.add(productDo);
        packageAdd.setProductList(productDos);
        packageAddList.add(packageAdd);
        orderOutputDo.setPackageList(packageAddList);
        String value = orderOutputService.add(orderOutputDo, userId);
        if (value == null) {
            return SingleResult.success();
        } else {
            return SingleResult.failure(value);
        }
    }

    @Override
    public SingleResult openApiSendOut(StockRecordSendReq req, Long userId, Long companyId) {
        //校验余额是否不足
        sufficientFundsCheck(companyId);

        //todo 有些属性需要填充，后续要补上
        StockRecordDo stockRecordDo = dao.selectById(req.getId());
        ProductInfoDo productInfoDo = productInfoDao.selectById(stockRecordDo.getProductInfoId());
        OpenApiOrderOutputAddReq orderOutputDo = new OpenApiOrderOutputAddReq();
//        orderOutputDo.setOrderType(1);//一件代发
        orderOutputDo.setSendDate(new Date());
        orderOutputDo.setShopId(stockRecordDo.getShopId());
        orderOutputDo.setStorageId(stockRecordDo.getStorageId());
//        orderOutputDo.setCompanyId(stockRecordDo.getCompanyId());
        orderOutputDo.setReceiverName(req.getReceiveName());
        orderOutputDo.setTelPhone(req.getTelephone());
        orderOutputDo.setPostCode(req.getPostCode());
        orderOutputDo.setArea(req.getArea());
        orderOutputDo.setAddress(req.getReceiveAddress().replaceAll("\n", ""));
//        orderInputDo.setTips(req.getRemark());
        orderOutputDo.setCod(req.getCod());
        if (StringUtils.isNotBlank(req.getDeliveryDate())) {
            orderOutputDo.setDeliveryDate(req.getDeliveryDate());
        }
        orderOutputDo.setDeliveryTime(req.getDeliveryTime());
        orderOutputDo.setShipmentType(req.getShipmentType());
        orderOutputDo.setOrderNo(req.getOrderNumber().trim());
//        packageDo.setLength(null);
//        packageDo.setWidth(null);
//        packageDo.setHeight(null);
//        packageDo.setHeight(null);
//        packageDo.setWeight(null);

        List<OpenApiOrderOutputProductAddReq> productList = new ArrayList<>();
        OpenApiOrderOutputProductAddReq openApiOrderOutputProductAddReq = new OpenApiOrderOutputProductAddReq();
        openApiOrderOutputProductAddReq.setCount(req.getCount());
        openApiOrderOutputProductAddReq.setCommoditySku(productInfoDo.getCommoditySku());
        productList.add(openApiOrderOutputProductAddReq);
        orderOutputDo.setProductList(productList);
        SingleResult value = orderOutputService.openApiAdd(orderOutputDo, companyId, userId);
        return value;
    }


    private void sufficientFundsCheck(Long companyId) {
        if (!companyAccountService.getIsDue(companyId)) {
            throw new NotSufficientFundsException(ErrorEnum.NOT_SUFFICIENT_FUNDS);
        }
    }

    //查询分页列表之后对列表数据的处理
    private List<StockRecordPageRes> handlerListAfter(List<StockRecordPageDto> list) {
        List<StockRecordPageRes> result = new ArrayList<>();
        if (!CollectionUtils.isEmpty(list)) {
            for (StockRecordPageDto pageDto : list) {
                StockRecordPageRes res = new StockRecordPageRes();
                res.setId(pageDto.getId());
                res.setCanotSellCount(pageDto.getCanotSellCount());
                res.setProductInfoId(pageDto.getProductInfoId());
                res.setProductId(pageDto.getProductId());
                res.setProductHeight(pageDto.getHeight());
                res.setProductWidth(pageDto.getWidth());
                res.setProductLength(pageDto.getLength());
                res.setProductWeight(pageDto.getWeight());
                res.setCasePack(pageDto.getCasePack());
                res.setProductType(pageDto.getProductType());
                res.setCanSellCount(pageDto.getCanSellCount());
                res.setCommoditySku(pageDto.getCommoditySku());
                res.setStorageSku(pageDto.getStorageSku());
                res.setStorage(pageDto.getStorageSku());
                res.setShopId(pageDto.getShopId());
                res.setStorageId(pageDto.getStorageId());
                res.setProductName(pageDto.getProductName());
                res.setNoDelivered(pageDto.getNoDelivered() + pageDto.getTurnFba());
                res.setJustNoDelivered(pageDto.getNoDelivered());
                res.setTurnFba(pageDto.getTurnFba());
                res.setInTransit(pageDto.getInTransit());
                res.setFreezeCount(pageDto.getFreezeCount());
                res.setUpdateTime(pageDto.getUpdateTime());
                ShopDo shopDo = shopDao.selectById(pageDto.getShopId());
                if (shopDo != null) {
                    res.setShop(shopDo.getShopName());
                }
                StorageDo storageDo = storageDao.selectById(pageDto.getStorageId());
                if (storageDo != null) {
                    res.setStorage(storageDo.getStorageName());
                }
                result.add(res);
            }
        }
        return result;
    }

    private IPage<StockRecordPageDto> pageInit(Map<String, String> map) {
        IPage<StockRecordPageDto> page = new Page();
        page.setSize(StringUtils.isNotBlank(map.get("pageSize")) ? Long.parseLong(map.get("pageSize")) : 10);
        page.setCurrent(StringUtils.isNotBlank(map.get("current")) ? Long.parseLong(map.get("current")) : 1);
        return page;
    }

    private IPage<StockTurnoverRateDto> turnoverRatPageInit(Map<String, String> map) {
        IPage<StockTurnoverRateDto> page = new Page();
        page.setSize(StringUtils.isNotBlank(map.get("pageSize")) ? Long.parseLong(map.get("pageSize")) : 10);
        page.setCurrent(StringUtils.isNotBlank(map.get("current")) ? Long.parseLong(map.get("current")) : 1);
        return page;
    }

    @Override
    public PageResult<StockTurnoverRatePageRes> turnoverRateList(Map<String, String> map) {
        IPage<StockTurnoverRateDto> page = turnoverRatPageInit(map);
        List<StockTurnoverRateDto> pageDtoList = dao.turnoverRateList(page, map);
        List<StockTurnoverRatePageRes> resList = handlerTurnoverRateListAfter(pageDtoList);
        PageResult result = new PageResult(resList, (int) page.getCurrent(), (int) page.getSize(), (int) page.getTotal(), (int) page.getPages());
        return result;
    }

    private List<StockTurnoverRatePageRes> handlerTurnoverRateListAfter(List<StockTurnoverRateDto> pageDtoList) {
        List<StockTurnoverRatePageRes> ratePageResList = new ArrayList<>();
        ExchangeRateDo exchangeRateDo = getExchageRate();
        for (StockTurnoverRateDto rateDo :
                pageDtoList) {
            StockTurnoverRatePageRes ratePageRes1 = new StockTurnoverRatePageRes();
            BeanUtils.copyProperties(rateDo, ratePageRes1);
            ShopDo shopDo = shopDao.selectById(rateDo.getShopId());
            if (shopDo != null)
                ratePageRes1.setShopName(shopDo.getShopName());
            CompanyDo companyDo = companyDao.selectById(rateDo.getCompanyId());
            if (companyDo != null)
                ratePageRes1.setCompanyCode(companyDo.getCompanyCode());
            double totalStockPrice = rateDo.getStockPriceStart() + rateDo.getStockPriceEnd();
            if (totalStockPrice == 0) {
                ratePageRes1.setTotalRate(0);
            } else {
                if (exchangeRateDo != null) {
                    ratePageRes1.setTotalRate(numberFormte(2 * (rateDo.getAmazonSalePrice() + rateDo.getRakutenSalePrice() * exchangeRateDo.getRate()) / totalStockPrice));
                } else {
                    ratePageRes1.setTotalRate(numberFormte(2 * (rateDo.getAmazonSalePrice() + rateDo.getRakutenSalePrice()) / totalStockPrice));
                }
            }
            ratePageResList.add(ratePageRes1);
        }
        return ratePageResList;
    }

    private ExchangeRateDo getExchageRate() {
        QueryWrapper wrapper1 = new QueryWrapper();
        wrapper1.orderByDesc("id");
        wrapper1.eq("type", DicBusinessItemConstant.amazon);
        wrapper1.last("limit 1");
        return rateDao.selectOne(wrapper1);
    }

    private double numberFormte(double v) {
        return new BigDecimal(v).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
    }

    @Override
    public SingleResult turnoverRateTotal(Map<String, String> map) {
        Double stockPriceTotal = dao.turnoverRateTotal(map);
        ExchangeRateDo exchangeRateDo = getExchageRate();

//        double stockPriceTotal = 0;
//        if (stockPriceList.size() > 0)
//            stockPriceTotal = stockPriceList.stream().filter(Objects::nonNull).mapToDouble(Integer::intValue).sum();
        double rakutenSale = dao.getRakutenRate(map.get("shopId"), map.get("companyId"), map.get("startDate"), map.get("endDate"));
        double amazonSale = dao.getAmazonRate(map.get("shopId"), map.get("companyId"), map.get("startDate"), map.get("endDate"));
        if (stockPriceTotal == null || stockPriceTotal == 0) return SingleResult.success(0);
        double rate = (amazonSale + rakutenSale) * 2 * exchangeRateDo.getRate() / stockPriceTotal;
        return SingleResult.success(new BigDecimal(rate).setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString());
    }

    @Override
    public Map stockAge(Long id) {
        Map<String, Integer> map = new HashMap<>();
        StockRecordDo stockRecordDo = dao.selectById(id);
        if (stockRecordDo == null) throw new BizExceptionI18(SysConstant.Stock_Notfound);
        ProductInfoDo productInfoDo = productInfoDao.selectById(stockRecordDo.getProductInfoId());
        int v1Count = stockLogService.selectInCount(stockRecordDo.getStorageId(), stockRecordDo.getShopId(),
                stockRecordDo.getProductInfoId(), productInfoDo.getCommoditySku(), 60);

        if (stockRecordDo.getCanSellCount() > v1Count) {
            map.put("v1Count", v1Count);
            int v2Count = stockLogService.selectInCount(stockRecordDo.getStorageId(), stockRecordDo.getShopId(),
                    stockRecordDo.getProductInfoId(), productInfoDo.getCommoditySku(), 180);
            int v3Count = stockRecordDo.getCanSellCount() - v2Count;

            if (stockRecordDo.getCanSellCount() > v2Count) {
                map.put("v2Count", v2Count - v1Count);
            } else {
                map.put("v2Count", stockRecordDo.getCanSellCount() - v1Count);
            }
            if (v3Count < 1) {
                map.put("v3Count", 0);
            } else {
                map.put("v3Count", v3Count);
            }
        } else {
            map.put("v1Count", stockRecordDo.getCanSellCount());
            map.put("v2Count", 0);
            map.put("v3Count", 0);
        }
        return map;
    }


    /******************库存快照模块************************/
    private IPage<StockSnapshotPageDto> StockSnapshotPageInit(Map<String, String> map) {
        IPage<StockSnapshotPageDto> page = new Page();
        page.setSize(StringUtils.isNotBlank(map.get("pageSize")) ? Long.parseLong(map.get("pageSize")) : 10);
        page.setCurrent(StringUtils.isNotBlank(map.get("current")) ? Long.parseLong(map.get("current")) : 1);
        return page;
    }

    @Override
    public PageResult getStockSnapshotPage(Map<String, String> map) {
        IPage<StockSnapshotPageDto> page = StockSnapshotPageInit(map);
        List<StockSnapshotPageDto> resList = dao.getStockSnapshotList(page, map);
        for (StockSnapshotPageDto stockSnapshotPageDto : resList) {
            stockSnapshotPageDto.setStockType(StringsUtil.createI18Message(stockSnapshotPageDto.getStockType()));
        }
        PageResult result = new PageResult(resList, (int) page.getCurrent(), (int) page.getSize(), (int) page.getTotal(), (int) page.getPages());
        return result;
    }

    @Override
    public  List<StockSnapshotExportVo> getStockSnapExportList(Map<String, String> map) {
        List<StockSnapshotPageDto> list = dao.getStockSnapshotList(map);
        if (list.size() > 99999) {
            throw new BizExceptionI18(SysConstant.File_Export_ToMuch, 100000);
        }
        List<StockSnapshotExportVo> exportVoList = new ArrayList<>();
        list.forEach(et -> {
            StockSnapshotExportVo exportVo = BeanConvert.INSTANCE.stockSnapshotExportVo(et);
            float size = (float) (exportVo.getLength() + exportVo.getWidth() + exportVo.getHeight());
            double backStorageFee = orderBackService.getBackStorageFee(size, exportVo.getBackCanSell() + exportVo.getBackCanotSell(), 1);
            exportVo.setBackFee(backStorageFee);
            exportVo.setNormalFee(MathUtils.sub(exportVo.getFee(), backStorageFee));
            exportVoList.add(exportVo);
        });
        return exportVoList;
    }

    @Override
    public String exportExcel(Map<String, String> map, String fileName) throws IOException {
        List<StockSnapshotExportVo> exportVoList = this.getStockSnapExportList(map);
        ExportParams exportParams = new ExportParams();
        exportParams.setCreateHeadRows(true);
        exportParams.setHeaderColor(IndexedColors.YELLOW.getIndex());

        ExcelUtils.exportExcelToSave(exportVoList, StockSnapshotExportVo.class, fileName, exportParams, filePathTemp);
        String objectNameTemporary = "";
        try {
            objectNameTemporary = AliOss.temporaryFile2(fileName, new File(filePathTemp + File.separator + fileName));
        } catch (Exception e) {
            e.printStackTrace();
            log.error("导出文件失败" + e.getMessage());
        }
        return fileUrl + objectNameTemporary;
    }


    /**
     * 导出库存明细 按单号 真实的先进先出明细
     */

    @Override
    public void exportProductStockDetail(Map<String, String> map, HttpServletResponse response) {
        CompanyDo companyDo = companyDao.selectById(map.get("companyId"));
        if (companyDo == null) {
            throw new BizException(SysConstant.Login_Error_Company);
        }
        List<ProductStockExportVo> exportVoList = this.getStockExportListReal(map);
        ExportParams exportParams = new ExportParams();
        exportParams.setCreateHeadRows(true);
        exportParams.setHeaderColor(IndexedColors.YELLOW.getIndex());
        try {
            ExcelUtils.exportExcel(exportVoList, ProductStockExportVo.class, companyDo.getCompanyCode() + "库存库龄详情" + TimeUtils.getCurrentDateTimeFormat(), exportParams, response);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    public List<ProductStockExportVo> getStockExportListReal(Map<String, String> map) {
        List<ProductStockDto> list = dao.getProductStockDetail(map);

        List<ProductStockExportVo> exportVoList = new ArrayList<>();
        for (ProductStockDto productStockDto : list) {
            ProductStockExportVo exportVo = new ProductStockExportVo();
            BeanUtils.copyProperties(productStockDto, exportVo);
            exportVoList.add(exportVo);
        }
        return exportVoList;
    }


    /**
     * 伪造的先进先出 给客户看
     *
     * @param map
     * @param response
     */
    @Override
    public void exportProductStockDetailFalse(Map<String, String> map, HttpServletResponse response) {
        CompanyDo companyDo = companyDao.selectById(map.get("companyId"));
        if (companyDo == null) {
            throw new BizException("请先选择公司");
        }
        if (StringUtils.isBlank(map.get("storageId"))) {
            map.put("storageId", "13");
        }
        StorageDo storageDo = storageService.getById(map.get("storageId"));
        if (storageDo == null) {
            throw new BizException(SysConstant.Pls_Chose_Storage);
        }
        List<ProductStockExportVo> exportVoList = this.getStockExportList(map);
        ExportParams exportParams = new ExportParams();
        exportParams.setCreateHeadRows(true);
        exportParams.setHeaderColor(IndexedColors.YELLOW.getIndex());
        try {
            ExcelUtils.exportExcel(exportVoList, ProductStockExportVo.class, companyDo.getCompanyCode() + "__" + storageDo.getStorageName() + "库存库龄详情" + TimeUtils.getCurrentDateTimeFormat(), exportParams, response);
        } catch (IOException e) {
            e.printStackTrace();
        }


    }


    public List<ProductStockExportVo> getStockExportList(Map<String, String> map) {
        //一个公司 一个仓库下 所有库存
        List<StockDayTotalDto> stockTotal = productStockRackDao.getStockTotalOldTable(map);
        List<StockHistoryDaysDto> historyList = productStockRackDao.getStockHistory(map);
        Map<String, List<StockHistoryDaysDto>> hisCollect = historyList.stream().collect(Collectors.groupingBy(i -> i.getStorageId() + "_" + i.getProductId()));

        List<ProductStockExportVo> exportVoList = new ArrayList<>();


        for (StockDayTotalDto key : stockTotal) {
            List<StockHistoryDaysDto> productHisList = hisCollect.get(key.getStorageId() + "_" + key.getProductId());
            if (productHisList == null) {
                continue;
            }
            int goodQuantity = key.getGoodQuantity();
            int badQuantity = key.getBadQuantity();
            for (StockHistoryDaysDto his : productHisList) {
                if ("良品".equals(his.getType())) {
                    if (goodQuantity <= 0) {
                        continue;
                    }

                    if (goodQuantity >= his.getQuantity()) {
                        goodQuantity -= his.getQuantity();
                    } else {
                        his.setQuantity(goodQuantity);
                        goodQuantity = 0;
                    }
                } else if ("次品".equals(his.getType())) {
                    if (badQuantity <= 0) {
                        continue;
                    }
                    if (badQuantity >= his.getQuantity()) {
                        badQuantity -= his.getQuantity();
                    } else {
                        his.setQuantity(badQuantity);
                        badQuantity = 0;
                    }
                } else {
                    continue;
                }
                ProductStockExportVo exportVo = new ProductStockExportVo();
                BeanUtils.copyProperties(his, exportVo);
                exportVoList.add(exportVo);
                if (goodQuantity <= 0 && badQuantity <= 0) {
                    break;
                }
            }
        }
        return exportVoList;
    }


    private IPage<StockRecordNewDto> pageInitNew(Map<String, String> map) {
        IPage<StockRecordNewDto> page = new Page<>();
        page.setSize(StringUtils.isNotBlank(map.get("pageSize")) ? Long.parseLong(map.get("pageSize")) : 10);
        page.setCurrent(StringUtils.isNotBlank(map.get("current")) ? Long.parseLong(map.get("current")) : 1);
        return page;
    }


    /**
     * 获取所有库存 不按店铺分
     */
    @Override
    public PageResult getStockListGroupCompany(Map<String, String> map) {
        IPage<StockRecordNewDto> page = pageInitNew(map);
        page = dao.getStockListGroupCompany(page, map);
        PageResult result = new PageResult(page.getRecords(), (int) page.getCurrent(), (int) page.getSize(), (int) page.getTotal(), (int) page.getPages());
        return result;
    }


    @Override
    public void freezeStock(Long productId, Long storageId, Long shopId, int type, int freezeCount, Long userId) {
        if (freezeCount == 0) {
            return;
        }

        ProductInfoDo productInfoDo = productInfoDao.selectObject(productId);
        if (productInfoDo == null) {
            throw new BizException(SysConstant.Product_NotExist);
        }
        LambdaQueryWrapper<StockRecordDo> stockWrapper = new LambdaQueryWrapper<>();
        stockWrapper.eq(StockRecordDo::getProductInfoId, productId)
                .eq(StockRecordDo::getStorageId, storageId)
                .eq(StockRecordDo::getShopId, shopId);
        StockRecordDo stockRecordDo;
        //减去OMS库存表
        synchronized (this) {
            stockRecordDo = dao.selectOne(stockWrapper);
        }
        if (stockRecordDo == null) {
            throw new BizException(SysConstant.Product_Stock_NotEnough, productInfoDo.getCommoditySku());
        }


        if (stockRecordDo.getCanSellCount() < freezeCount) {
            throw new BizException(SysConstant.Product_Stock_NotEnough, productInfoDo.getCommoditySku());
        }
        //冻结
        stockRecordDo.setCanSellCount(stockRecordDo.getCanSellCount() - freezeCount);
        stockRecordDo.setFreezeCount(stockRecordDo.getFreezeCount() + freezeCount);

        dao.updateById(stockRecordDo);

        stockLogService.saveAutoSendOutLog(productInfoDo.getId(), stockRecordDo.getShopId(), stockRecordDo.getStorageId(),
                -freezeCount, stockRecordDo.getCanSellCount(), stockRecordDo.getCompanyId(), "冻结库存", userId);
    }


    /**
     * 冻结库存
     *
     * @param productId
     * @param userId
     */
    @Override
    public void freezeStock(Long productId, Long userId) {
        List<StockRecordDo> list = dao.selectList(new LambdaQueryWrapper<StockRecordDo>()
                .eq(StockRecordDo::getProductInfoId, productId));
        for (StockRecordDo recordDo : list) {
            if (recordDo.getCanSellCount() == 0) {
                continue;
            }
            this.freezeStock(productId, recordDo.getStorageId(), recordDo.getShopId(), 0, recordDo.getCanSellCount(), userId);
        }
    }

    /**
     * @param companyId
     * @param shopId
     * @param storageId
     * @param productId
     * @param count
     * @return canUseCount
     */
    @Override
    public int getStockCount(Long companyId, Long shopId, Long storageId, Long productId, Integer count) {
        int canUseCount = 0;
        CompanyDo companyDo = companyDao.selectById(companyId);

        LambdaQueryWrapper<StockRecordDo> wrapper2 = new LambdaQueryWrapper();
        wrapper2.eq(StockRecordDo::getShopId, shopId).eq(StockRecordDo::getProductInfoId, productId).eq(StockRecordDo::getStorageId, storageId);
        StockRecordDo stockRecordDo = dao.selectOne(wrapper2);
        if (stockRecordDo == null) {
            canUseCount = 0;
        }else {
            int noDeliveredCount1 = dao.getOrderOutCount(productId, shopId, storageId) + dao.getOrderOutTurn2FbaCount(productId, shopId, storageId);
            canUseCount = stockRecordDo.getCanSellCount() - noDeliveredCount1;
        }
            //进行调货操作
        if (canUseCount < count &&companyDo.getAutoStock()==1) {
            List<ShopDo> shopDoList = shopDao.selectList(new LambdaQueryWrapper<ShopDo>().eq(ShopDo::getCompanyId, companyId));
            for (ShopDo shopDo : shopDoList) {
                wrapper2=new LambdaQueryWrapper<>();
                wrapper2.eq(StockRecordDo::getShopId, shopDo.getId())
                        .eq(StockRecordDo::getProductInfoId, productId)
                        .eq(StockRecordDo::getStorageId, storageId);
                StockRecordDo stockRecordDo2 = dao.selectOne(wrapper2);
                int noDeliveredCount2 = dao.getOrderOutCount(productId, shopDo.getId(), storageId)
                        + dao.getOrderOutTurn2FbaCount(productId, shopDo.getId(), storageId);
                if (stockRecordDo2 != null && stockRecordDo2.getCanSellCount() - noDeliveredCount2 >= count) {

                    StockTransferAddReq addReq = new StockTransferAddReq();
                    addReq.setShopInId(shopId);
                    addReq.setShopOutId(shopDo.getId());
                    addReq.setOrderForm(1);
                    List<StockTransferProductAdd> productAddList = new ArrayList<>();
                    StockTransferProductAdd productAdd = new StockTransferProductAdd();
                    productAdd.setProductId(productId);
                    productAdd.setCount(count);
                    productAdd.setStorageId(storageId);
                    productAddList.add(productAdd);
                    addReq.setDetailList(productAddList);
                    boolean b = stockTransferService.add(addReq, 1L, companyId, false);
                    if (b)
                        return count;
                }
            }
        }
        return canUseCount;
    }
}
